#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
测试闭包变量的符号查找机制
"""

import ast
from mcpy.ir.module import IRModule
from mcpy.symbol_table import SymbolKind


class TestClosureVariables:
    """闭包变量测试类"""

    def test_basic_closure(self):
        """测试基本闭包场景"""
        code = """
def outer_func(x: int) -> callable:
    outer_var = x * 2
    
    def inner_func(y: int) -> int:
        return outer_var + y  # outer_var是闭包变量
    
    return inner_func
"""

        tree = ast.parse(code)
        ir_module = IRModule()
        ir_module.build_from_ast(tree)

        # 查找外部函数
        outer_func_node = ir_module.find_symbol_ir_node(
            "outer_func", SymbolKind.FUNCTION
        )
        assert outer_func_node is not None

        # 查找内部函数
        inner_func_symbol = outer_func_node.lookup_symbol("inner_func")
        assert inner_func_symbol is not None
        inner_func_node = inner_func_symbol.ir_node
        assert inner_func_node is not None

        # 测试闭包变量查找
        outer_var_in_inner = inner_func_node.lookup_symbol("outer_var")
        assert outer_var_in_inner is not None
        assert outer_var_in_inner.kind == SymbolKind.CLOSURE_VARIABLE
        assert outer_var_in_inner.name == "outer_var"

    def test_parameter_closure(self):
        """测试参数作为闭包变量"""
        code = """
def outer_func(param: int) -> callable:
    def inner_func() -> int:
        return param * 2  # param是闭包变量（来自外部函数参数）
    
    return inner_func
"""

        tree = ast.parse(code)
        ir_module = IRModule()
        ir_module.build_from_ast(tree)

        # 查找函数和内部函数
        outer_func_node = ir_module.find_symbol_ir_node(
            "outer_func", SymbolKind.FUNCTION
        )
        assert outer_func_node is not None

        inner_func_symbol = outer_func_node.lookup_symbol("inner_func")
        assert inner_func_symbol is not None
        inner_func_node = inner_func_symbol.ir_node
        assert inner_func_node is not None

        # 测试参数闭包变量
        param_in_inner = inner_func_node.lookup_symbol("param")
        assert param_in_inner is not None
        assert param_in_inner.kind == SymbolKind.CLOSURE_VARIABLE
        assert param_in_inner.name == "param"

    def test_variable_shadowing(self):
        """测试变量遮蔽（不应该是闭包变量）"""
        code = """
def outer_func() -> callable:
    outer_var = 10
    
    def inner_func() -> int:
        outer_var = 20  # 这里定义了同名局部变量，遮蔽外部变量
        return outer_var
    
    return inner_func
"""

        tree = ast.parse(code)
        ir_module = IRModule()
        ir_module.build_from_ast(tree)

        # 查找函数
        outer_func_node = ir_module.find_symbol_ir_node(
            "outer_func", SymbolKind.FUNCTION
        )
        assert outer_func_node is not None

        inner_func_symbol = outer_func_node.lookup_symbol("inner_func")
        assert inner_func_symbol is not None
        inner_func_node = inner_func_symbol.ir_node
        assert inner_func_node is not None

        # 测试变量遮蔽：应该找到局部变量，不是闭包变量
        outer_var_in_inner = inner_func_node.lookup_symbol("outer_var")
        assert outer_var_in_inner is not None
        assert (
            outer_var_in_inner.kind == SymbolKind.VARIABLE
        )  # 应该是局部变量，不是闭包变量
        assert outer_var_in_inner.name == "outer_var"

    def test_multi_level_closure(self):
        """测试多层嵌套闭包"""
        code = """
def level1_func(x: int) -> callable:
    level1_var = x
    
    def level2_func(y: int) -> callable:
        level2_var = y
        
        def level3_func(z: int) -> int:
            # level1_var和level2_var都是闭包变量
            return level1_var + level2_var + z
        
        return level3_func
    
    return level2_func
"""

        tree = ast.parse(code)
        ir_module = IRModule()
        ir_module.build_from_ast(tree)

        # 查找level1函数
        level1_node = ir_module.find_symbol_ir_node("level1_func", SymbolKind.FUNCTION)
        assert level1_node is not None

        # 查找level2函数
        level2_symbol = level1_node.lookup_symbol("level2_func")
        assert level2_symbol is not None
        level2_node = level2_symbol.ir_node
        assert level2_node is not None

        # 查找level3函数
        level3_symbol = level2_node.lookup_symbol("level3_func")
        assert level3_symbol is not None
        level3_node = level3_symbol.ir_node
        assert level3_node is not None

        # 测试多层闭包变量
        level1_var_in_level3 = level3_node.lookup_symbol("level1_var")
        assert level1_var_in_level3 is not None
        assert level1_var_in_level3.kind == SymbolKind.CLOSURE_VARIABLE

        level2_var_in_level3 = level3_node.lookup_symbol("level2_var")
        assert level2_var_in_level3 is not None
        assert level2_var_in_level3.kind == SymbolKind.CLOSURE_VARIABLE

    def test_no_closure_global_access(self):
        """测试访问全局变量（不是闭包变量）"""
        code = """
global_var = 100

def func() -> int:
    return global_var  # 这是全局变量访问，不是闭包
"""

        tree = ast.parse(code)
        ir_module = IRModule()
        ir_module.build_from_ast(tree)

        # 查找函数
        func_node = ir_module.find_symbol_ir_node("func", SymbolKind.FUNCTION)
        assert func_node is not None

        # 测试全局变量访问：应该找到变量，但不是闭包变量
        global_var_in_func = func_node.lookup_symbol("global_var")
        assert global_var_in_func is not None
        assert global_var_in_func.kind == SymbolKind.VARIABLE  # 全局变量，不是闭包变量

    def test_method_closure(self):
        """测试类方法中的闭包变量"""
        code = """
class MyClass:
    def outer_method(self, x: int) -> callable:
        outer_var = x * 2
        
        def inner_func(y: int) -> int:
            return outer_var + y  # outer_var是闭包变量
        
        return inner_func
"""

        tree = ast.parse(code)
        ir_module = IRModule()
        ir_module.build_from_ast(tree)

        # 查找类
        class_node = ir_module.find_symbol_ir_node("MyClass", SymbolKind.CLASS)
        assert class_node is not None

        # 查找外部方法
        outer_method_symbol = class_node.lookup_symbol("outer_method")
        assert outer_method_symbol is not None
        outer_method_node = outer_method_symbol.ir_node
        assert outer_method_node is not None

        # 查找内部函数
        inner_func_symbol = outer_method_node.lookup_symbol("inner_func")
        assert inner_func_symbol is not None
        inner_func_node = inner_func_symbol.ir_node
        assert inner_func_node is not None

        # 测试闭包变量查找
        outer_var_in_inner = inner_func_node.lookup_symbol("outer_var")
        assert outer_var_in_inner is not None
        assert outer_var_in_inner.kind == SymbolKind.CLOSURE_VARIABLE
        assert outer_var_in_inner.name == "outer_var"

    def test_closure_with_same_name_parameter(self):
        """测试闭包变量与参数同名的情况"""
        code = """
def outer_func(shared_name: int) -> callable:
    def inner_func(shared_name: str) -> str:
        # 这里的shared_name是参数，不是闭包变量
        return shared_name
    
    return inner_func
"""

        tree = ast.parse(code)
        ir_module = IRModule()
        ir_module.build_from_ast(tree)

        # 查找函数
        outer_func_node = ir_module.find_symbol_ir_node(
            "outer_func", SymbolKind.FUNCTION
        )
        assert outer_func_node is not None

        inner_func_symbol = outer_func_node.lookup_symbol("inner_func")
        assert inner_func_symbol is not None
        inner_func_node = inner_func_symbol.ir_node
        assert inner_func_node is not None

        # 测试同名参数：应该找到参数，不是闭包变量
        shared_name_in_inner = inner_func_node.lookup_symbol("shared_name")
        assert shared_name_in_inner is not None
        assert (
            shared_name_in_inner.kind == SymbolKind.PARAMETER
        )  # 应该是参数，不是闭包变量
